//==================================================================
//  Copyright (C) 2006-2007  Davide Pasca
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//==================================================================
///
///
///
///
///
//==================================================================

#ifndef MENU_H
#define MENU_H

#include <string.h>
#include "psys.h"
#include "guibase.h"
//#include "pwindow.h"

//==================================================================
typedef void	*MenuUserDataPtr;
	
//==================================================================
/// RadioList
//==================================================================
class RadioList
{
public:
	int				*_userdatap;
	int				_from_val;
	int				_from_idx;
	int				_n;

	int				_ref_cnt;

	RadioList( int *userdatap, int from_val, int from_idx, int n ) :
	_userdatap(userdatap),
	_from_val(from_val),
	_from_idx(from_idx),
	_n(n),
	_ref_cnt(0)
	{
	}

	int	GetValFromIdx( int idx ) const
	{
		int	loc_idx = idx - _from_idx;
		
		PASSERT( loc_idx >= 0 && loc_idx < _n );

		return loc_idx + _from_val;
	}

	int	GetIdxFromVal( int val ) const
	{
		int	loc_idx = val - _from_val;

		PASSERT( loc_idx >= 0 && loc_idx < _n );

		return loc_idx + _from_idx;
	}

	void SetSelIdx( int idx )
	{
		*_userdatap = GetValFromIdx( idx );
	}

	int GetSelIdx() const
	{
		return GetIdxFromVal( *_userdatap );
	}

	void AddRef()
	{
		++_ref_cnt;
	}

	void SubRef()
	{
		if ( --_ref_cnt == 0 )
		{
			delete this;	// self-destruct !!!
		}
	}
};

//==================================================================
/// MenuItem
//==================================================================
class MenuItem
{
public:
	enum Type
	{
		TYPE_NORMAL,
		TYPE_TITLE,
		TYPE_EMPTY,
		TYPE_CHECK,
		TYPE_TOGGLE_ITEM,
		TYPE_RADIOLIST_ITEM,
		TYPE_SUBMENU,
	};

private:
	//==================================================================
	TCHAR			_name[128];
	int				_type;

	MenuUserDataPtr	_userdatap;

	RadioList		*_radiolistp;
	int				_radio_idx;

	int				_flags;
	int				_y;
	int				_width, _h;

	bool			_selected;

	class Menu		*_submenup;

public:
	//==================================================================
	MenuItem( MenuUserDataPtr userdatap, MenuItem::Type type, const TCHAR *namep );
	MenuItem( RadioList *radiolistp, const TCHAR *namep );
	MenuItem( bool *toggle_valp, const TCHAR *namep );
	MenuItem( const TCHAR *namep, class Menu *submenup );
	~MenuItem();

	//-------- toggle item
	bool	Toggle();

	void	SetCheck( bool onoff );
	bool	GetCheck() const;

	void	SetName( const TCHAR *namep )
	{
		_tcscpy_s( _name, namep );
	}

private:
	void baseInit();

	friend class Menu;
};

//==================================================================
typedef void	(*MenuCallback)( void *menu_userdatap, class Menu *menup, MenuUserDataPtr userdatap );

//==================================================================
/// Menu
//==================================================================
class Menu
{
	bool				_visible;
	bool				_active;
	bool				_is_popup;

	int					_flags;
	int					_disp_w, _disp_h;

	Menu				*_activity_childp;

	int					_x, _y;
	int					_w, _h;

	int					_last_mouse_offset_x;
	int					_last_mouse_offset_y;

	int					_cur_sel_item;
	int					_lbutt_down_sel_item;

	std::vector<MenuItem *>	_itemsp;

	MenuCallback		_callback;
	void				*_callback_userdatap;

public:
	GuiBaseManager		_base_manager;

public:
	//==================================================================
	Menu();
	~Menu()
	{
		for (int i=0; i < _itemsp.size(); ++i)
			delete _itemsp[i];
	}
	//==================================================================
	//void	AddItem( MenuItemID userdatap, const TCHAR *namep );
	//void	AddItem( const TCHAR *namep )
	//{
	//	return AddItem( NULL, namep );
	//}
private:
	void	addItem( MenuUserDataPtr userdatap, MenuItem::Type type, const TCHAR *namep );
	void	addItem( RadioList *radiolistp, const TCHAR *namep );

public:
	void	AddNormalItem( MenuUserDataPtr userdatap, const TCHAR *namep );
	void	AddTitleItem( MenuUserDataPtr userdatap, const TCHAR *namep );
	void	AddEmptyItem( MenuUserDataPtr userdatap, const TCHAR *namep );
	void	AddCheckItem( bool *userdatap, const TCHAR *namep );
	void	AddToggleItem( bool *userdatap, const TCHAR *namep );
	void	AddSubmenu( const TCHAR *namep, class Menu *submenup );

	void	SetItemText( MenuUserDataPtr userdatap, const TCHAR *textp );

	void	RemoveItem( MenuUserDataPtr userdatap );

private:
	//==================================================================
	struct RadioListMaker
	{
		RadioList	*_radiolistp;
		int			_cur_val;

		RadioListMaker() :
			_radiolistp(NULL),
			_cur_val(0)
		{
		}

		void Reset( RadioList *radiolistp )
		{
			PASSERT( _radiolistp == NULL );
			_radiolistp = radiolistp;
			_cur_val = 0;
		}
		
		void End()
		{
			_radiolistp->SubRef();
			_radiolistp = NULL;
		}

		void	NextVal()
		{
			_cur_val += 1;
		}

		bool	ItemMatchesCurVal() const
		{
			return ( _cur_val == *_radiolistp->_userdatap );

		}
	} _RadioListMaker;
public:
	//==================================================================
	void	BeginRadioList( int *userdatap, int from_val );
	void	AddRadioItem( const TCHAR *namep );
	void	EndRadioList();

	//==================================================================
	void	ItemSetCheck( bool *userdatap )
	{
		ItemSetCheck( userdatap, *userdatap );
	}

	//==================================================================
	// NOMORE bool	ItemSetCheckExclusive( MenuUserDataPtr userdatap, bool *list[] );

	void	ItemSetCheck( MenuUserDataPtr userdatap, bool onoff );
	bool	ItemGetCheck( MenuUserDataPtr userdatap ) const;
	bool	ItemToggleCheck( MenuUserDataPtr userdatap );

	//==================================================================
	void	SetCallback( MenuCallback cback, void *userdatap )
	{
		_callback = cback;
		_callback_userdatap = userdatap;
	}

	//==================================================================
	void	SetPos( int x, int y );
	void	Show( bool onoff );
	void	SetPopup( bool onoff );

	//==================================================================
	bool	IsShowing() const
	{
		return _visible;
	}
	//==================================================================
	void	Reset();
private:
	void	redraw();
	void	redrawSub();

public:
	static int		EventFilter_s( void *userdatap, class WindowEvent *eventp );
	int				EventFilter( class WindowEvent *eventp, Menu *parent_menup );

	bool	GetClickedItem( u_int *item_idp );

private:
	//==================================================================
	void	invalidate() const
	{
		_base_manager.InvalidateDisplay();
	}
	//==================================================================
	void	recalcGeometry();
	void	do_free();
	//==================================================================
	int		find_item( int px, int py ) const;
	void	handleMove( int x, int y, int w, int h );
	void	handleDragging( int x, int y );
	bool	isPointInside( int x, int y ) const;
	int		find_item_by_id( MenuUserDataPtr userdatap ) const;
};

//==================================================================
#define MENU_ITEM_FLG_TITLE		1
#define MENU_ITEM_FLG_EMPTY		2
#define MENU_ITEM_FLG_CHECKABLE	4
#define MENU_ITEM_FLG_CHECKON	8

#endif